#include "Thread.hpp" // IWYU pragma: keep
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
using namespace std;
using namespace ThreadMoudle;

int InitClient() {
  int sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
  if (sockfd < 0) {
    cerr << "create socket,error" << endl;
    exit(1);
  }
  return sockfd;
}

void RecvMessage(int sockfd, const string &name) {
  while(true){
    struct sockaddr_in peer;
    socklen_t len = sizeof(peer);

    char buffer[1024];
    int n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0,
                        (struct sockaddr *)&peer, &len);
    if (n > 0) {
      buffer[n] = 0;
      cerr << buffer << endl;
    } 
    else {
      cerr<<"recvfrom error"<<endl;
      break;
    }
  }
}

void SendMessage(int sockfd, string serverip, uint16_t serverport,const string &name) {
  
  struct sockaddr_in server;
  memset(&server, 0, sizeof(server));
  server.sin_family = AF_INET;
  server.sin_port = htons(serverport);
  server.sin_addr.s_addr = inet_addr(serverip.c_str());

  string cli_profix = name +'#';
  while(true)
  {
    string line;
    cout << cli_profix;
    getline(cin, line);

    int n =sendto(sockfd, line.c_str(), line.size(), 0, (struct sockaddr*)&server,sizeof(server)); // 消息发给谁
    if(n<=0)
    {
      break;
    }
  }
}

// 客户端在未来一定要知道服务器的IP地址和端口号
int main(int argc, char *argv[]) {
  if (argc != 3) {
    cerr << "Usage: " << argv[0] << "server-ip server-port" << endl;
    exit(0);
  }
  string serverip = argv[1];
  uint16_t serverport = stoi(argv[2]);

  int sockfd = InitClient();

  Thread recver("recver-thread", bind(&RecvMessage, sockfd, placeholders::_1));
  Thread sender("sender-thread", bind(&SendMessage, sockfd, serverip,serverport, placeholders::_1));

  recver.Start();
  sender.Start();

  recver.Join();
  sender.Join();

  ::close(sockfd);

  return 0;
}